package rsj.proxy.bind;

import org.springframework.stereotype.Component;
import rsj.proxy.parse.ParamTypeEnum;
import rsj.proxy.parse.ParameterMapping;
import rsj.proxy.parse.SqlSource;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;

/**
 * 参数是集合数据类型-解析
 *
 * @author yuanqinglong
 * @since 2021/5/27 15:59
 */
@Component
public class CollectionParamResolveProcessor implements ParamResolveProcessor {



    @Override
    public ParamTypeEnum getSupportType() {
        return ParamTypeEnum.COLLECTION;
    }


    @Override
    public void doParamResolve(SqlSource sqlSource, ParameterMapping parameterMapping,
                               Method method, Object[] args, List<Object> resolveParamList) {
        // 获取占位符在所有占位符中的位置、将这个位置的? 替换为集合元素个数个?
        // 例: 集合中有三个元素
        // 原始SQL:   SELECT * FROM user WHERE id IN (?)  --------
        // 替换后SQL: SELECT * FROM user WHERE id IN (?,?,?)   <--|
        int index = sqlSource.getParameterMappings().indexOf(parameterMapping);
        Collection<?> collection = (Collection<?>) args[parameterMapping.getMethodParamIndex()];
        // sql占位符名称和形参名称对应的参数下标
        if (collection.size() > 1) {
            // 根据IN参数集合元素个数 组装对应个数? 占位符
            String assembly = this.assemblyInQueryConditions(collection);
            // 组装完整的 IN 查询sql
            String sql = this.supplementInQuery(sqlSource.getSql(), index + 1, assembly);
            sqlSource.setFinalSql(sql);
        }
        resolveParamList.addAll((Collection<?>) args[parameterMapping.getMethodParamIndex()]);
    }


    /**
     * 补充在查询
     *
     * @param sql        sql
     * @param paramNum   要替换的问号的序号
     * @param supplement 补充
     * @return {@link String}
     */
    public String supplementInQuery(String sql, Integer paramNum, String supplement) {
        int theNumberOfOccurrences = 0;
        char[] chars = sql.toCharArray();
        for (int i1 = 0; i1 < chars.length; i1++) {
            if (chars[i1] == '?') {
                theNumberOfOccurrences++;
                if (theNumberOfOccurrences == paramNum) {
                    String anteriorSegment = sql.substring(0, i1);
                    return anteriorSegment + supplement + sql.substring(i1 + 1);
                }
            }
        }
        return sql;
    }


    public String assemblyInQueryConditions(Collection<?> collection) {
        StringBuilder values = new StringBuilder();
        for (int i = 0; i < collection.size(); i++) {
            if (i > 0) {
                values.append(",");
            }
            values.append("?");
        }
        return values.toString();
    }
}
